/*
 * PlayListPanel.java
 *
 * Created on June 15, 2005, 10:06 PM
 */
package com.bff.slimserver.musicjukebox.ui;

import com.bff.slimserver.music.exceptions.PlaylistException;
import com.bff.slimserver.musicjukebox.lib.actions.PlaylistRemoveAlbumAction;
import com.bff.slimserver.musicjukebox.lib.actions.PlaylistShuffleAlbumsAction;
import com.bff.slimserver.musicjukebox.lib.actions.PlaylistLoopAction;
import com.bff.slimserver.musicjukebox.lib.actions.SongLoopAction;
import com.bff.slimserver.musicjukebox.lib.actions.PlaylistAddArtistAction;
import com.bff.slimserver.musicjukebox.lib.actions.PlaylistAddAlbumAction;
import com.bff.slimserver.musicjukebox.lib.actions.PlaylistRemoveArtistAction;
import com.bff.slimserver.musicjukebox.lib.actions.PlaylistShuffleSongAction;
import com.bff.slimserver.musicjukebox.lib.JukeboxProperties;
import com.bff.slimserver.musicjukebox.lib.actions.AddFavoriteAction;
import com.bff.slimserver.musicjukebox.lib.events.PlayerChosenEvent;
import com.bff.slimserver.musicjukebox.lib.events.PlayerChosenListener;
import com.bff.bjj.ui.component.BJJPanel;
import com.bff.slimserver.musicjukebox.ui.components.PlaylistCellRenderer;
import com.bff.slimserver.musicjukebox.ui.components.PlaylistPopupMenu;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.*;
import javax.swing.*;
import com.bff.bjj.utils.Utils;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.logging.Level;
import org.apache.log4j.Logger;
import org.bff.slimserver.SlimDatabase;
import org.bff.slimserver.SlimPlaylist;
import org.bff.slimserver.events.PlaylistChangeEvent;
import org.bff.slimserver.events.PlaylistChangeListener;
import org.bff.slimserver.events.TrackPositionChangeEvent;
import org.bff.slimserver.events.TrackPositionChangeListener;
import org.bff.slimserver.exception.SlimConnectionException;
import org.bff.slimserver.exception.SlimException;
import org.bff.slimserver.musicobjects.SlimArtist;
import org.bff.slimserver.musicobjects.SlimPlayableObject;
import org.bff.slimserver.musicobjects.SlimPlaylistItem;
import org.bff.slimserver.musicobjects.favorite.SlimFavoriteItem;

/**
 *
 * @author  Bill
 */
public class PlaylistPanel extends BJJPanel
        implements PlaylistChangeListener,
        TrackPositionChangeListener,
        PlayerChosenListener {

    private SlimPlaylist playlist;
    private SlimDatabase database;
    private DefaultListModel playlistSongsModel;
    private Action playlistLoopAction;
    private Action playlistRandomAction;
    private Action playlistRandomAlbumAction;
    private PlaylistAddArtistAction addArtistAction;
    private PlaylistRemoveArtistAction removeArtistAction;
    private AddFavoriteAction addArtistFavoriteAction;
    private PlaylistRemoveAlbumAction removeAlbumAction;
    private PlaylistAddAlbumAction addAlbumAction;
    private AddFavoriteAction addAlbumFavoriteAction;
    private Action songLoopAction;
    private SlimPlaylistItem currentObject;
    private Hashtable<String, SlimPlaylistItem> songTable;
    private PlaylistCellRenderer playlistRenderer;
    private Logger logger = Logger.getLogger("playlist");
    private static final int MAX_ARTWORK_SIZE = 500;
    private static final int MAX_ALBUM_ARTIST_LABEL = 25;

    /** Creates new form PlayListPanel */
    public PlaylistPanel() {
        logger.debug("Starting initialization of playlist panel.");
        try {
            this.playlist = JukeboxProperties.getInstance().getPlaylist();
        } catch (PlaylistException ex) {
            logger.error("Could not get playlist.", ex);
        }

        try {
            this.database = JukeboxProperties.getInstance().getDatabase();
        } catch (SlimConnectionException ex) {
            logger.error("Could not get database.", ex);
        }

        logger.trace("Creating structures for the playlist.");
        songTable = new Hashtable<String, SlimPlaylistItem>();
        this.playlistSongsModel = new DefaultListModel();

        makeActions();

        logger.trace("Starting the creation of ui components.");
        initComponents();
        logger.trace("Doen with the creation of ui components.");

        remove(playlistAlternateButtonPanel);

        btnPlaylistLoop.setAction(playlistLoopAction);
        btnSongLoop.setAction(songLoopAction);

        playlistRenderer = new PlaylistCellRenderer();
        listPlaylist.setCellRenderer(playlistRenderer);
        JukeboxProperties.getInstance().getSlimMonitor().addPlaylistChangeListener(this);
        JukeboxProperties.getInstance().addPlayerChosenListener(this);
        JukeboxProperties.getInstance().getSlimMonitor().addTrackPositionChangeListener(this);

        cbArtwork.setSelected(JukeboxProperties.getInstance().isPlaylistAlbumArt());

        logger.debug("Starting load of initial playlist songs.");
        listInitialSongs();
        logger.debug("Ending load of initial playlist songs.");

        MouseListener songlistPopupListener = new SonglistPopupListener();
        listPlaylist.addMouseListener(songlistPopupListener);

        try {
            if (getPlaylist().getItemCount() > 0) {
                setCurrentItem(getPlaylist().getCurrentItem());
            }
        } catch (SlimException ex) {
            logger.error("Could not set current playlist item.", ex);
        }
        
        progressBarLoadingPlaylist.setVisible(false);

        updateActions((SlimPlaylistItem) listPlaylist.getSelectedValue());

        logger.trace("Done with initialization of playlist panel.");
    }

    /**
     *
     * @param size
     */
    private void checkArtWorkAbility(int size) {
        if (size < MAX_ARTWORK_SIZE) {
            cbArtwork.setVisible(false);
        } else {
            cbArtwork.setVisible(false);
        }
    }

    private void setActionAbility(boolean b) {
        logger.trace("Setting action ability to " + b);
        addArtistAction.setEnabled(b);
        addAlbumAction.setEnabled(b);
        addAlbumFavoriteAction.setEnabled(b);
        addArtistFavoriteAction.setEnabled(b);
        removeArtistAction.setEnabled(b);
        removeAlbumAction.setEnabled(b);
        logger.trace("Done setting action ability to " + b);
    }

    private boolean usingArtwork(int size) {
        if (size < MAX_ARTWORK_SIZE) {
            return true;
        } else {
            return false;
        }
    }

    private SlimPlaylistItem getPlaylistItem(String id) {
        SlimPlaylistItem plSong = songTable.get(id);

        if (plSong == null) {

            SlimPlayableObject item = getDatabase().lookupItem(id.split("-")[1]);

            if (item != null) {
                plSong = new SlimPlaylistItem(item);
            } else {

                try {
                    String index = "";

                    if (id.contains("--")) {
                        index = "-" + id.split("-")[2];
                    } else {
                        index = id.split("-")[1];
                    }

                    plSong = new SlimPlaylistItem(getPlaylist().getRemoteItem(index));
                } catch (SlimException ex) {
                    logger.error("Error getting playlist remote item.", ex);
                }
            }
        }

        return plSong;
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        playListButtonPanel = new com.bff.bjj.ui.component.BJJPanel();
        btnRemoveSong = new com.bff.bjj.ui.component.BJJButton();
        btnAddArtist = new com.bff.bjj.ui.component.BJJButton();
        btnRemoveArtist = new com.bff.bjj.ui.component.BJJButton();
        btnAddAlbum = new com.bff.bjj.ui.component.BJJButton();
        btnRemoveAlbum = new com.bff.bjj.ui.component.BJJButton();
        btnRandomize = new com.bff.bjj.ui.component.BJJButton();
        btnRandomize.setAction(playlistRandomAction);
        btnSavePlaylist = new com.bff.bjj.ui.component.BJJButton();
        btnRemoveAll = new com.bff.bjj.ui.component.BJJButton();
        btnPlaylistLoop = new com.bff.bjj.ui.component.BJJButton();
        btnSongLoop = new com.bff.bjj.ui.component.BJJButton();
        cbArtwork = new javax.swing.JCheckBox();
        jPanel3 = new com.bff.bjj.ui.component.BJJPanel();
        spPlaylist = new javax.swing.JScrollPane();
        listPlaylist = new com.bff.slimserver.musicjukebox.ui.components.PlaylistSongList(playlistSongsModel);
        progressBarLoadingPlaylist = new javax.swing.JProgressBar();
        playlistAlternateButtonPanel = new com.bff.bjj.ui.component.BJJPanel();
        jPanel8 = new com.bff.bjj.ui.component.BJJPanel();
        jPanel7 = new com.bff.bjj.ui.component.BJJPanel();
        btnAddArtist1 = new com.bff.bjj.ui.component.BJJButton();
        btnRemoveArtist1 = new com.bff.bjj.ui.component.BJJButton();
        lblArtist = new javax.swing.JLabel();
        btnArtistFavorite = new com.bff.bjj.ui.component.BJJButton();
        jPanel6 = new com.bff.bjj.ui.component.BJJPanel();
        btnAddAlbum1 = new com.bff.bjj.ui.component.BJJButton();
        btnRemoveAlbum1 = new com.bff.bjj.ui.component.BJJButton();
        lblAlbum = new javax.swing.JLabel();
        btnAlbumFavorite = new com.bff.bjj.ui.component.BJJButton();
        jPanel9 = new com.bff.bjj.ui.component.BJJPanel();
        btnRandomize1 = new com.bff.bjj.ui.component.BJJButton();
        btnRemoveSong1 = new com.bff.bjj.ui.component.BJJButton();
        btnRemoveAll1 = new com.bff.bjj.ui.component.BJJButton();
        btnSavePlaylist1 = new com.bff.bjj.ui.component.BJJButton();
        btnPlaylistLoop1 = new com.bff.bjj.ui.component.BJJButton();
        btnSongLoop1 = new com.bff.bjj.ui.component.BJJButton();
        btnRandomizeAlbum = new com.bff.bjj.ui.component.BJJButton();
        btnSync = new com.bff.bjj.ui.component.BJJButton();
        cbRemoveSong = new javax.swing.JCheckBox();

        setPreferredSize(new java.awt.Dimension(258, 500));
        setLayout(new java.awt.BorderLayout());

        playListButtonPanel.setLayout(new java.awt.GridBagLayout());

        btnRemoveSong.setFont(new java.awt.Font("Tahoma", 0, 12));
        btnRemoveSong.setText("Remove Song");
        btnRemoveSong.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnRemoveSongActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        playListButtonPanel.add(btnRemoveSong, gridBagConstraints);

        btnAddArtist.setAction(addArtistAction);
        btnAddArtist.setFont(new java.awt.Font("Tahoma", 0, 12));
        btnAddArtist.setText("Add Artist");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        playListButtonPanel.add(btnAddArtist, gridBagConstraints);

        btnRemoveArtist.setAction(removeArtistAction);
        btnRemoveArtist.setFont(new java.awt.Font("Tahoma", 0, 12));
        btnRemoveArtist.setText("Remove Artist");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 4;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        playListButtonPanel.add(btnRemoveArtist, gridBagConstraints);

        btnAddAlbum.setAction(addAlbumAction);
        btnAddAlbum.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
        btnAddAlbum.setText("Add Album");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        playListButtonPanel.add(btnAddAlbum, gridBagConstraints);

        btnRemoveAlbum.setAction(removeAlbumAction);
        btnRemoveAlbum.setFont(new java.awt.Font("Tahoma", 0, 12));
        btnRemoveAlbum.setText("Remove Album");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        playListButtonPanel.add(btnRemoveAlbum, gridBagConstraints);

        btnRandomize.setFont(new java.awt.Font("Tahoma", 0, 12));
        btnRandomize.setText("Shuffle Songs");
        btnRandomize.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnRandomizeActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 5;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        playListButtonPanel.add(btnRandomize, gridBagConstraints);

        btnSavePlaylist.setFont(new java.awt.Font("Tahoma", 0, 12));
        btnSavePlaylist.setText("Save Playlist");
        btnSavePlaylist.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnSavePlaylistActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 5;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        playListButtonPanel.add(btnSavePlaylist, gridBagConstraints);

        btnRemoveAll.setFont(new java.awt.Font("Tahoma", 0, 12));
        btnRemoveAll.setText("Clear");
        btnRemoveAll.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnRemoveAllActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 4;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        playListButtonPanel.add(btnRemoveAll, gridBagConstraints);

        btnPlaylistLoop.setFont(new java.awt.Font("Tahoma", 0, 12));
        btnPlaylistLoop.setText("Loop Playlist");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        playListButtonPanel.add(btnPlaylistLoop, gridBagConstraints);

        btnSongLoop.setFont(new java.awt.Font("Tahoma", 0, 12));
        btnSongLoop.setText("Loop Song");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        playListButtonPanel.add(btnSongLoop, gridBagConstraints);

        cbArtwork.setSelected(true);
        cbArtwork.setText("Artwork");
        cbArtwork.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cbArtworkActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        playListButtonPanel.add(cbArtwork, gridBagConstraints);

        add(playListButtonPanel, java.awt.BorderLayout.SOUTH);

        jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder("Current Playlist"));
        jPanel3.setLayout(new java.awt.BorderLayout());

        listPlaylist.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                listPlaylistMouseClicked(evt);
            }
        });
        spPlaylist.setViewportView(listPlaylist);

        jPanel3.add(spPlaylist, java.awt.BorderLayout.CENTER);

        progressBarLoadingPlaylist.setIndeterminate(true);
        progressBarLoadingPlaylist.setRequestFocusEnabled(false);
        progressBarLoadingPlaylist.setString("Loading Playlist");
        progressBarLoadingPlaylist.setStringPainted(true);
        jPanel3.add(progressBarLoadingPlaylist, java.awt.BorderLayout.SOUTH);

        add(jPanel3, java.awt.BorderLayout.CENTER);

        playlistAlternateButtonPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Playlist Actions"));
        playlistAlternateButtonPanel.setLayout(new java.awt.GridBagLayout());

        jPanel8.setLayout(new java.awt.GridBagLayout());

        jPanel7.setBorder(javax.swing.BorderFactory.createTitledBorder("Artist"));
        jPanel7.setMinimumSize(new java.awt.Dimension(200, 140));
        jPanel7.setPreferredSize(new java.awt.Dimension(200, 140));
        jPanel7.setLayout(new java.awt.GridBagLayout());

        btnAddArtist1.setAction(addArtistAction);
        btnAddArtist1.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
        btnAddArtist1.setMaximumSize(new java.awt.Dimension(125, 25));
        btnAddArtist1.setMinimumSize(new java.awt.Dimension(125, 25));
        btnAddArtist1.setPreferredSize(new java.awt.Dimension(125, 25));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        jPanel7.add(btnAddArtist1, gridBagConstraints);

        btnRemoveArtist1.setAction(removeArtistAction);
        btnRemoveArtist1.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
        btnRemoveArtist1.setMaximumSize(new java.awt.Dimension(125, 25));
        btnRemoveArtist1.setMinimumSize(new java.awt.Dimension(125, 25));
        btnRemoveArtist1.setPreferredSize(new java.awt.Dimension(125, 25));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        jPanel7.add(btnRemoveArtist1, gridBagConstraints);

        lblArtist.setText(" ");
        jPanel7.add(lblArtist, new java.awt.GridBagConstraints());

        btnArtistFavorite.setAction(addArtistFavoriteAction);
        btnArtistFavorite.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
        btnArtistFavorite.setMaximumSize(new java.awt.Dimension(125, 25));
        btnArtistFavorite.setMinimumSize(new java.awt.Dimension(125, 25));
        btnArtistFavorite.setPreferredSize(new java.awt.Dimension(125, 25));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        jPanel7.add(btnArtistFavorite, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 0;
        jPanel8.add(jPanel7, gridBagConstraints);

        jPanel6.setBorder(javax.swing.BorderFactory.createTitledBorder("Album"));
        jPanel6.setMinimumSize(new java.awt.Dimension(200, 140));
        jPanel6.setPreferredSize(new java.awt.Dimension(200, 140));
        jPanel6.setLayout(new java.awt.GridBagLayout());

        btnAddAlbum1.setAction(addAlbumAction);
        btnAddAlbum1.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
        btnAddAlbum1.setMaximumSize(new java.awt.Dimension(125, 25));
        btnAddAlbum1.setMinimumSize(new java.awt.Dimension(125, 25));
        btnAddAlbum1.setPreferredSize(new java.awt.Dimension(125, 25));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        jPanel6.add(btnAddAlbum1, gridBagConstraints);

        btnRemoveAlbum1.setAction(removeAlbumAction);
        btnRemoveAlbum1.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
        btnRemoveAlbum1.setMaximumSize(new java.awt.Dimension(125, 25));
        btnRemoveAlbum1.setMinimumSize(new java.awt.Dimension(125, 25));
        btnRemoveAlbum1.setPreferredSize(new java.awt.Dimension(125, 25));
        btnRemoveAlbum1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnRemoveAlbum1ActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        jPanel6.add(btnRemoveAlbum1, gridBagConstraints);

        lblAlbum.setText(" ");
        jPanel6.add(lblAlbum, new java.awt.GridBagConstraints());

        btnAlbumFavorite.setAction(addAlbumFavoriteAction);
        btnAlbumFavorite.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
        btnAlbumFavorite.setMaximumSize(new java.awt.Dimension(125, 25));
        btnAlbumFavorite.setMinimumSize(new java.awt.Dimension(125, 25));
        btnAlbumFavorite.setPreferredSize(new java.awt.Dimension(125, 25));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        jPanel6.add(btnAlbumFavorite, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        jPanel8.add(jPanel6, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        playlistAlternateButtonPanel.add(jPanel8, gridBagConstraints);

        jPanel9.setLayout(new java.awt.GridBagLayout());

        btnRandomize1.setAction(getPlaylistRandomAction());
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        jPanel9.add(btnRandomize1, gridBagConstraints);

        btnRemoveSong1.setText("Remove Song");
        btnRemoveSong1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnRemoveSong1ActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        jPanel9.add(btnRemoveSong1, gridBagConstraints);

        btnRemoveAll1.setText("Clear");
        btnRemoveAll1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnRemoveAll1ActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        jPanel9.add(btnRemoveAll1, gridBagConstraints);

        btnSavePlaylist1.setText("Save");
        btnSavePlaylist1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnSavePlaylist1ActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        jPanel9.add(btnSavePlaylist1, gridBagConstraints);

        btnPlaylistLoop1.setAction(getPlaylistLoopAction());
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        jPanel9.add(btnPlaylistLoop1, gridBagConstraints);

        btnSongLoop1.setAction(getSongLoopAction());
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        jPanel9.add(btnSongLoop1, gridBagConstraints);

        btnRandomizeAlbum.setAction(getPlaylistRandomAlbumAction());
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        jPanel9.add(btnRandomizeAlbum, gridBagConstraints);

        btnSync.setText("ReSync");
        btnSync.setToolTipText("Click if playlist seems out of sync with SC");
        btnSync.setMaximumSize(new java.awt.Dimension(97, 23));
        btnSync.setMinimumSize(new java.awt.Dimension(97, 23));
        btnSync.setPreferredSize(new java.awt.Dimension(97, 23));
        btnSync.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnSyncActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
        jPanel9.add(btnSync, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        playlistAlternateButtonPanel.add(jPanel9, gridBagConstraints);

        cbRemoveSong.setText("Remove song after playing");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        playlistAlternateButtonPanel.add(cbRemoveSong, gridBagConstraints);

        add(playlistAlternateButtonPanel, java.awt.BorderLayout.PAGE_START);
    }// </editor-fold>//GEN-END:initComponents

    private void listPlaylistMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_listPlaylistMouseClicked

        new Thread(new Runnable() {

            @Override
            public void run() {
                updateActions((SlimPlaylistItem) listPlaylist.getSelectedValue());
            }
        }).start();

        if (evt.getClickCount() == 2) {
            try {
                getPlaylist().playItem((SlimPlaylistItem) listPlaylist.getSelectedValue());
            } catch (SlimException ex) {
                logger.error("Error playing playlist item.", ex);
            }
        } else {
            JList lstCust = (JList) evt.getSource();
            int currIndex = lstCust.locationToIndex(evt.getPoint());
            SlimPlaylistItem currData = (SlimPlaylistItem) lstCust.getSelectedValue();
            Rectangle itemBounds = lstCust.getCellBounds(currIndex, currIndex);
            Point currPoint = new Point(evt.getX(), evt.getY());
            Component readyComponent = ((PlaylistCellRenderer) lstCust.getCellRenderer()).getListCellRendererComponent(lstCust,
                    currData, currIndex, true, true);
            readyComponent.setSize(itemBounds.width, itemBounds.height);
            Component pressedComponent = null;
            while (readyComponent != pressedComponent) {
                if (pressedComponent != null) {
                    readyComponent = pressedComponent;
                }
                pressedComponent = readyComponent.getComponentAt((int) (currPoint.getX() - itemBounds.getX()),
                        (int) (currPoint.getY() - itemBounds.getY()));

                if (pressedComponent == null) {
                    return;
                }
                currPoint.setLocation(currPoint.getX() - itemBounds.getX(), currPoint.getY() - itemBounds.getY());
                itemBounds = pressedComponent.getBounds();
            }

            if (pressedComponent instanceof JButton) {
                ((JButton) pressedComponent).doClick();
            }

            getPlaylistRenderer().getListPanels().get(currData.getId()).eventReceived(evt);
        }
    }//GEN-LAST:event_listPlaylistMouseClicked

private void btnRemoveSong1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRemoveSong1ActionPerformed
    try {
        setCursor(Utils.getHourglassCursor());
        Object selObject[] = listPlaylist.getSelectedValues();
        for (int i = 0; i < selObject.length; i++) {
            try {
                getPlaylist().removeItem((SlimPlaylistItem) selObject[i]);
            } catch (SlimException ex) {
                logger.error("Error removing playlist item.", ex);
            }
        }
    } finally {
        setCursor(Utils.getNormalCursor());
    }
}//GEN-LAST:event_btnRemoveSong1ActionPerformed

private void btnRemoveAll1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRemoveAll1ActionPerformed
    try {
        setCursor(Utils.getHourglassCursor());
        getPlaylist().clear();
    } catch (SlimException ex) {
        logger.error("Error clearing playlist.", ex);
    } finally {
        setCursor(Utils.getNormalCursor());
    }
}//GEN-LAST:event_btnRemoveAll1ActionPerformed

private void btnSavePlaylist1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSavePlaylist1ActionPerformed
    savePlaylist();
}//GEN-LAST:event_btnSavePlaylist1ActionPerformed

private void btnSyncActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSyncActionPerformed
    resync();
}//GEN-LAST:event_btnSyncActionPerformed

private void cbArtworkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbArtworkActionPerformed
    listPlaylist.setCellRenderer(null);

    SplashScreen sp = new SplashScreen(Utils.getParentComponent(this), true);
    sp.toFront();

    try {
        if (cbArtwork.isSelected()) {
            sp.setMainTextArea("\n\nLoading album art");
        } else {
            sp.setMainTextArea("\n\nLoading album panels");
        }
        int size = playlistSongsModel.size();

        sp.setProgressbarMax(size);
        sp.setProgressBarLabel("Loading song ");

        int count = 1;


        for (Enumeration e = playlistSongsModel.elements(); e.hasMoreElements();) {

            SlimPlaylistItem song = (SlimPlaylistItem) e.nextElement();
            //listPanels.remove(song);

            //if (cbArtwork.isSelected()) {
            //    listPanels.put(song, new PlaylistCellWithArtPanel(song, listPlaylist, (int) ((count - 1) / 10.0 * 1000)));
            //} else {
            //listPanels.put(song, new PlaylistCellPanel(song, listPlaylist));
            //}
            sp.setProgressBarLabel("Loading song " + (count++) + " of " + size);
        }
    } finally {
        sp.setStopped(true);
    }
    logger.trace("Ending artwork click load");

    listPlaylist.setCellRenderer(new PlaylistCellRenderer());
    new Thread(new Runnable() {

        @Override
        public void run() {
            if (cbArtwork.isSelected()) {
                JukeboxProperties.getInstance().setPlaylistAlbumArt(true);
            } else {
                JukeboxProperties.getInstance().setPlaylistAlbumArt(false);
            }
        }
    }).start();
}//GEN-LAST:event_cbArtworkActionPerformed

private void btnRemoveAllActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRemoveAllActionPerformed
    try {
        setCursor(Utils.getHourglassCursor());
        getPlaylist().clear();
    } catch (SlimException ex) {
        logger.error("Error clearing playlist.", ex);
    } finally {
        setCursor(Utils.getNormalCursor());
    }
}//GEN-LAST:event_btnRemoveAllActionPerformed

private void btnSavePlaylistActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSavePlaylistActionPerformed
    savePlaylist();
}//GEN-LAST:event_btnSavePlaylistActionPerformed

private void btnRandomizeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRandomizeActionPerformed
    try {
        setCursor(Utils.getHourglassCursor());
        getPlaylist().shuffleItems();
    } catch (SlimException ex) {
        logger.error("Error shuffling playlist items.", ex);
    } finally {
        setCursor(Utils.getNormalCursor());
    }
}//GEN-LAST:event_btnRandomizeActionPerformed

private void btnRemoveSongActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRemoveSongActionPerformed
    try {
        setCursor(Utils.getHourglassCursor());
        Object selObject[] = listPlaylist.getSelectedValues();
        for (int i = 0; i < selObject.length; i++) {
            try {
                getPlaylist().removeItem((SlimPlaylistItem) selObject[i]);
            } catch (SlimException ex) {
                logger.error("Error removing playlist item.", ex);
            }
        }
    } finally {
        setCursor(Utils.getNormalCursor());
    }
}//GEN-LAST:event_btnRemoveSongActionPerformed

private void btnRemoveAlbum1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRemoveAlbum1ActionPerformed
    // TODO add your handling code here:
}//GEN-LAST:event_btnRemoveAlbum1ActionPerformed
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnAddAlbum;
    private javax.swing.JButton btnAddAlbum1;
    private javax.swing.JButton btnAddArtist;
    private javax.swing.JButton btnAddArtist1;
    private javax.swing.JButton btnAlbumFavorite;
    private javax.swing.JButton btnArtistFavorite;
    private javax.swing.JButton btnPlaylistLoop;
    private javax.swing.JButton btnPlaylistLoop1;
    private javax.swing.JButton btnRandomize;
    private javax.swing.JButton btnRandomize1;
    private javax.swing.JButton btnRandomizeAlbum;
    private javax.swing.JButton btnRemoveAlbum;
    private javax.swing.JButton btnRemoveAlbum1;
    private javax.swing.JButton btnRemoveAll;
    private javax.swing.JButton btnRemoveAll1;
    private javax.swing.JButton btnRemoveArtist;
    private javax.swing.JButton btnRemoveArtist1;
    private javax.swing.JButton btnRemoveSong;
    private javax.swing.JButton btnRemoveSong1;
    private javax.swing.JButton btnSavePlaylist;
    private javax.swing.JButton btnSavePlaylist1;
    private javax.swing.JButton btnSongLoop;
    private javax.swing.JButton btnSongLoop1;
    private javax.swing.JButton btnSync;
    private javax.swing.JCheckBox cbArtwork;
    private javax.swing.JCheckBox cbRemoveSong;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JPanel jPanel6;
    private javax.swing.JPanel jPanel7;
    private javax.swing.JPanel jPanel8;
    private javax.swing.JPanel jPanel9;
    private javax.swing.JLabel lblAlbum;
    private javax.swing.JLabel lblArtist;
    private javax.swing.JList listPlaylist;
    private javax.swing.JPanel playListButtonPanel;
    private javax.swing.JPanel playlistAlternateButtonPanel;
    private javax.swing.JProgressBar progressBarLoadingPlaylist;
    private javax.swing.JScrollPane spPlaylist;
    // End of variables declaration//GEN-END:variables

    @Override
    public synchronized void playlistChanged(PlaylistChangeEvent pce) {
        switch (pce.getId()) {
            case PlaylistChangeEvent.ITEM_CHANGED:
                if (isRemoveSongAfterPlay()) {
                    if ((getCurrentItem().getLength() - getCurrentElapsedTime()) < 5) {
                        try {
                            getPlaylist().removeItem(getCurrentItem());
                            refreshPlaylist();
                        } catch (SlimException ex) {
                            java.util.logging.Logger.getLogger(PlaylistPanel.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                } else {
                    try {
                        setCurrentItem(getPlaylist().getCurrentItem());
                    } catch (SlimException ex) {
                        logger.error("Error setting playlist current item.", ex);
                    }
                }
                break;
            case PlaylistChangeEvent.ITEM_ADDED:
            case PlaylistChangeEvent.ITEM_DELETED:
                refreshPlaylist();
                break;
            case PlaylistChangeEvent.ITEM_LOADED:
            case PlaylistChangeEvent.ITEM_INSERTED:
                resync();
                break;
            case PlaylistChangeEvent.PLAYLIST_CHANGED:
                if (checkPlaylist(new ArrayList<SlimPlaylistItem>(pce.getNewPlaylist()))) {
                    refreshPlaylist();
                }
                break;

            case PlaylistChangeEvent.REPEAT_OFF:
            case PlaylistChangeEvent.REPEAT_PLAYLIST:
            case PlaylistChangeEvent.REPEAT_ITEM:
                try {
                    ((PlaylistLoopAction) getPlaylistLoopAction()).checkStatus();
                    ((SongLoopAction) getSongLoopAction()).checkStatus();
                } catch (SlimException ex) {
                    logger.error("Error checking repeat status", ex);
                }
                break;
            case PlaylistChangeEvent.SHUFFLE_ITEMS:
            case PlaylistChangeEvent.SHUFFLE_ALBUMS:
            case PlaylistChangeEvent.SHUFFLE_OFF:
                resync();
                break;
            default:
                refreshPlaylist();
                break;
        }

        //always repaint
        try {
            listPlaylist.repaint();
            repaint();
            Utils.getParentComponent(this).repaint();
        } catch (NullPointerException npe) {
            //don't care
            //might get this at startup
        }
    }

    private void makeActions() {
        logger.trace("Starting action creation.");
        setPlaylistLoopAction(new PlaylistLoopAction(getPlaylist()));
        setPlaylistRandomAction(new PlaylistShuffleSongAction(getPlaylist()));
        setPlaylistRandomAlbumAction(new PlaylistShuffleAlbumsAction(playlist));
        setSongLoopAction(new SongLoopAction(getPlaylist()));
        addArtistAction = new PlaylistAddArtistAction(playlist, null, true);
        removeArtistAction = new PlaylistRemoveArtistAction(playlist, null, true);
        addArtistFavoriteAction = new AddFavoriteAction((SlimFavoriteItem) null, true);
        addAlbumAction = new PlaylistAddAlbumAction(playlist, null, true);
        removeAlbumAction = new PlaylistRemoveAlbumAction(playlist, null, true);
        addAlbumFavoriteAction = new AddFavoriteAction((SlimFavoriteItem) null, true);
        logger.trace("Done with action creation.");
    }

    public void setSelectedSong(SlimPlaylistItem song) {
        listPlaylist.setSelectedValue(song, true);
    }

    private synchronized void listInitialSongs() {
        SplashScreen sp = new SplashScreen(Utils.getParentComponent(this), true);
        sp.toFront();

        try {
            sp.setMainTextArea("\n\nGetting Playlist");
            List<SlimPlaylistItem> songList = new ArrayList<SlimPlaylistItem>(getPlaylist().getItems());
            playlistSongsModel.clear();

            int size = songList.size();

            checkArtWorkAbility(size);

            int count = 1;
            sp.setMainTextArea("\n\nLoading Playlist");
            sp.setProgressbarMax(size);
            sp.setProgressBarLabel("Loading song ");
            for (SlimPlaylistItem playlistSong : songList) {
                playlistSongsModel.addElement(playlistSong);
                songTable.put(playlistSong.getPlaylistIndex() + "-" + playlistSong.getId(), playlistSong);
                //listPanels.put(playlistSong, new PlaylistCellPanel(playlistSong, listPlaylist));
                sp.setProgressBarLabel("Loading song " + (count++) + " of " + size);
            }
            listPlaylist.setModel(playlistSongsModel);
            revalidate();
        } catch (SlimException ex) {
            logger.error("Error getting initial playlist song list.", ex);
        } finally {
            sp.setStopped(true);
        }
    }

    private synchronized void listSongs() {

        try {
            progressBarLoadingPlaylist.setVisible(true);
            listPlaylist.setEnabled(false);

            List<SlimPlaylistItem> songIdList =
                    new ArrayList<SlimPlaylistItem>(getPlaylist().getItemIds());

            if (songIdList.size() < 1) {
                resync();
                return;
            }

            checkArtWorkAbility(songIdList.size());

            //first we have to see if any songs need removing
            if (songIdList.size() > 0) {
                if (playlistSongsModel.size() > songIdList.size()) {
                    int count = playlistSongsModel.size() - songIdList.size();
                    int c = 0;
                    List<Integer> indexestoRemove = new ArrayList<Integer>();
                    for (int i = 0; i < playlistSongsModel.size(); i++) {
                        SlimPlaylistItem item = (SlimPlaylistItem) playlistSongsModel.get(i);
                        if (!songIdList.contains(item)) {
                            indexestoRemove.add(i);
                            if (count == (++c)) {
                                break;
                            }
                        }

                    }

                    //have to go backwards for removal
                    for (int i = indexestoRemove.size() - 1; i > -1; --i) {
                        SlimPlaylistItem item = (SlimPlaylistItem) playlistSongsModel.remove(indexestoRemove.get(i));
                        songTable.remove(item.getPlaylistIndex() + "-" + item.getId());
                    }
                }
            }

            SlimPlaylistItem playlistSong = null;


            for (int i = 0; i < songIdList.size(); i++) {
                playlistSong = songIdList.get(i);
                try {
                    SlimPlaylistItem song = (SlimPlaylistItem) playlistSongsModel.get(i);

                    if (!song.getId().equalsIgnoreCase(playlistSong.getId())
                            || song.getPlaylistIndex() != playlistSong.getPlaylistIndex()) {

                        SlimPlaylistItem plSong = songTable.remove(song.getPlaylistIndex() + "-" + song.getId());
                        plSong.setPlaylistIndex(playlistSong.getPlaylistIndex());
                        playlistSongsModel.set(i, plSong);
                        songTable.put(plSong.getPlaylistIndex() + "-" + plSong.getId(), plSong);
                    }
                } catch (ArrayIndexOutOfBoundsException e) {
                    if (playlistSongsModel.size() > songIdList.size()) {
                        SlimPlaylistItem song = (SlimPlaylistItem) playlistSongsModel.remove(i);
                        songTable.remove(song.getPlaylistId());
                    } else {
                        SlimPlaylistItem plSong = getPlaylistItem(playlistSong.getPlaylistIndex() + "-" + playlistSong.getId());
                        plSong.setPlaylistIndex(playlistSong.getPlaylistIndex());
                        playlistSongsModel.addElement(plSong);
                        songTable.put(plSong.getPlaylistIndex() + "-" + plSong.getId(), plSong);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            if (playlistSongsModel.size() < 2 && playlistSongsModel.size() > 0 && getPlaylistRenderer().getListPanels().size() > 0) {
                for (String key : getPlaylistRenderer().getListPanels().keySet()) {
                    getPlaylistRenderer().getListPanels().get(key).setUpAction(false);
                    getPlaylistRenderer().getListPanels().get(key).setDownAction(false);
                }
            } else {
                for (String key : getPlaylistRenderer().getListPanels().keySet()) {
                    if (getPlaylistRenderer().getListPanels().get(key) != null) {
                        getPlaylistRenderer().getListPanels().get(key).setUpAction(true);
                        getPlaylistRenderer().getListPanels().get(key).setDownAction(true);
                    }
                }
            }

            listPlaylist.repaint();

            if (getPlaylist().getItemCount() != playlistSongsModel.size()) {
                new Thread(new Runnable() {

                    public void run() {
                        resync();
                    }
                }).start();
            }

        } catch (SlimException ex) {
            logger.error("Error listing playlist songs.", ex);
        } finally {
            progressBarLoadingPlaylist.setVisible(false);
            listPlaylist.setEnabled(true);
        }
    }

    /**
     * True is needing to refresh
     * @param newPlaylist
     * @return
     */
    private synchronized boolean checkPlaylist(List<SlimPlaylistItem> newPlaylist) {

        if (playlistSongsModel.size() != newPlaylist.size()) {
            return true;
        }

        for (int i = 0; i < newPlaylist.size(); i++) {
            if (((SlimPlaylistItem) playlistSongsModel.get(i)).getId().equalsIgnoreCase(newPlaylist.get(i).getId())
                    || ((SlimPlaylistItem) playlistSongsModel.get(i)).getPlaylistIndex() != newPlaylist.get(i).getPlaylistIndex()) {
                return true;
            }
        }
        return false;
    }

    private SlimPlaylist getPlaylist() {
        return playlist;
    }

    private void setPlaylist(SlimPlaylist playlist) {
        this.playlist = playlist;
    }

    public SlimPlaylistItem getCurrentItem() {
        return currentObject;
    }

    public void setCurrentItem(SlimPlaylistItem object) {
        playlistRenderer.setCurrentItem(object);
        this.currentObject = object;
    }

    public void savePlaylist() {
        new SavePlaylistDialog(Utils.getParentComponent(this)).setVisible(true);
    }

    /**
     * @return the database
     */
    public SlimDatabase getDatabase() {
        return database;
    }

    /**
     * @param database the database to set
     */
    public void setDatabase(SlimDatabase database) {
        this.database = database;
    }

    /**
     * @return the playlistRandomAction
     */
    private Action getPlaylistRandomAction() {
        return playlistRandomAction;
    }

    /**
     * @param playlistRandomAction the playlistRandomAction to set
     */
    public void setPlaylistRandomAction(Action playlistRandomAction) {
        this.playlistRandomAction = playlistRandomAction;
    }

    /**
     * @return the playlistRandomAlbumAction
     */
    private Action getPlaylistRandomAlbumAction() {
        return playlistRandomAlbumAction;
    }

    /**
     * @param playlistRandomAlbumAction the playlistRandomAlbumAction to set
     */
    public void setPlaylistRandomAlbumAction(Action playlistRandomAlbumAction) {
        this.playlistRandomAlbumAction = playlistRandomAlbumAction;
    }

    /**
     * @return the addArtistAction
     */
    public PlaylistAddArtistAction getAddArtistAction() {
        return addArtistAction;
    }

    private void updateActions(SlimPlaylistItem item) {
        logger.trace("Updating playlist actions.");
        if (item != null && item instanceof SlimPlaylistItem) {

            SlimPlaylistItem song = (SlimPlaylistItem) item;
            try {
                lblAlbum.setText(song.getAlbum().getName().length() < MAX_ALBUM_ARTIST_LABEL ? song.getAlbum().getName() : song.getAlbum().getName().substring(0, MAX_ALBUM_ARTIST_LABEL));
                lblAlbum.setToolTipText(song.getAlbum().getName());
                lblArtist.setText(song.getArtist().length() < MAX_ALBUM_ARTIST_LABEL ? song.getArtist() : song.getArtist().substring(0, MAX_ALBUM_ARTIST_LABEL));
                lblArtist.setToolTipText(song.getArtist());
                setActionAbility(true);
                SlimArtist artist = new ArrayList<SlimArtist>(getDatabase().getArtistsForAlbum(song.getAlbum())).get(0);
                addArtistAction.setArtist(artist);
                removeArtistAction.setArtist(artist);
                addArtistFavoriteAction.setFavorite(artist);
                addAlbumAction.setAlbum(song.getAlbum());
                removeAlbumAction.setAlbum(song.getAlbum());
                addAlbumFavoriteAction.setFavorite(song.getAlbum());
            } catch (Exception ex) {
                logger.info("Failed updating playlist actions.  Disabling actions", ex);
                lblArtist.setText(null);
                lblAlbum.setText(null);
                setActionAbility(false);
            }
        } else {
            logger.debug("Playlist item was either null or an instance of something other than a SlimPlaylistItem.");
            lblArtist.setText(null);
            lblAlbum.setText(null);
            setActionAbility(false);
        }
    }

    /**
     * @return the playlistLoopAction
     */
    private Action getPlaylistLoopAction() {
        return playlistLoopAction;
    }

    /**
     * @param playlistLoopAction the playlistLoopAction to set
     */
    public void setPlaylistLoopAction(Action playlistLoopAction) {
        this.playlistLoopAction = playlistLoopAction;
    }

    /**
     * @return the songLoopAction
     */
    private Action getSongLoopAction() {
        return songLoopAction;
    }

    /**
     * @param songLoopAction the songLoopAction to set
     */
    public void setSongLoopAction(Action songLoopAction) {
        this.songLoopAction = songLoopAction;
    }
    private long currentElapsedTime = 0;

    public void trackPositionChanged(TrackPositionChangeEvent event) {
        setCurrentElapsedTime(event.getElapsedTime());
    }

    /**
     * @return the removeSongAfterPlay
     */
    public boolean isRemoveSongAfterPlay() {
        return cbRemoveSong.isSelected();
    }

    /**
     * @return the currentElapsedTime
     */
    public long getCurrentElapsedTime() {
        return currentElapsedTime;
    }

    /**
     * @param currentElapsedTime the currentElapsedTime to set
     */
    public void setCurrentElapsedTime(long currentElapsedTime) {
        this.currentElapsedTime = currentElapsedTime;
    }

    private void resync() {
        songTable = new Hashtable<String, SlimPlaylistItem>();
        playlistRenderer = new PlaylistCellRenderer();
        listPlaylist.setCellRenderer(playlistRenderer);
        this.playlistSongsModel = new DefaultListModel();

        new Thread(new Runnable() {

            public void run() {
                listInitialSongs();
            }
        }).start();
    }

    /**
     * @return the playlistRenderer
     */
    private PlaylistCellRenderer getPlaylistRenderer() {
        return playlistRenderer;
    }

    private class SonglistPopupListener extends MouseAdapter {

        public void mousePressed(MouseEvent evt) {
            if (SwingUtilities.isRightMouseButton(evt)) {
                maybeShowPopup(evt);
            }
        }

        public void mouseReleased(MouseEvent evt) {
            maybeShowPopup(evt);
        }

        private void maybeShowPopup(MouseEvent evt) {
            int row = listPlaylist.locationToIndex(evt.getPoint());

            if (row > -1) {
                listPlaylist.setSelectedIndex(row);

                SlimPlaylistItem song = (SlimPlaylistItem) playlistSongsModel.getElementAt(row);

                PlaylistPopupMenu popupMenu = new PlaylistPopupMenu(Utils.getParentComponent(evt.getComponent()), getPlaylist(), song);

                if (evt.isPopupTrigger()) {
                    popupMenu.show(evt.getComponent(),
                            evt.getX(), evt.getY());
                }
            }
        }
    }

    public void playerChosen(PlayerChosenEvent event) {
        resync();
    }

    public void setPlaylistButtonPanelGrid() {
        playListButtonPanel.setLayout(new GridLayout(3, 3));
    }

    public synchronized void refreshPlaylist() {
        listSongs();
        try {
            setCurrentItem(getPlaylist().getCurrentItem());
        } catch (SlimException ex) {
            logger.error("Error refreshing playlist.", ex);
        }
    }

    public void hideButtons() {
        playListButtonPanel.setVisible(false);
    }

    public void showButtons() {
        playListButtonPanel.setVisible(true);
    }

    public Object[] getSelectedValues() {
        return listPlaylist.getSelectedValues();
    }

    public JPanel getPlaylistAlternativeButtonPanel() {
        return playlistAlternateButtonPanel;
    }
}
